/**
 * @Copyright：<a href="www.wisesoft.net.cn">四川川大智胜系统集成有限公司</a>
 * @Author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
 * @CreateTime: 2022年08月03日  19:55
 */
package com.fxsen.commons.utils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.Map;
import java.util.Properties;

/**
 * 获得属性文件值的入口
 * 支持properties和yml
 * 支持在application.properties或application.yml中定义spring.profiles.active
 *@Author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
 *@CreateTime: 2022年08月03日  19:55
 */
public class PropertiesUtils implements IPropertiesUtils {
    private static final Logger log = LoggerFactory.getLogger(PropertiesUtils.class);
    private static final String SPRING_PROFILES_ACTIVE = null;
    private static final String APPLICATION_PROPERTIES = "application.properties";
    private static final String APPLICATION_YML = "application.yml";

    private static final PropertiesUtils INSTANCE = new PropertiesUtils();

    public static PropertiesUtils getInstance() {
        return INSTANCE;
    }
    /**
     * 获得属性文件key对应的
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:07
 	 * @param: is 输入流
 	 * @param: propertyName 属性名称
 	 * @param: closeStream 是否关闭流
 	 * @return: {@link String}
    **/
    public static String getValueByPropertyName(InputStream is, String propertyName, boolean closeStream){
        String s = "";
        if(is == null) {
            return s;
        }
        Properties p = new Properties();
        try {
            p.load(is);
            if(closeStream){
                is.close();
            }
            s = p.getProperty(propertyName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }
    /**
     * 获得属性文件key对应的
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:08
 	 * @param: is 输入流
 	 * @param: propertyName 属性名称
 	 * @param: closeStream 是否关闭流
 	 * @param: defaultValue 默认值
 	 * @return: {@link String}
    **/
    public static String getValueByPropertyName(InputStream is, String propertyName, boolean closeStream, String defaultValue) {
        String s = defaultValue;
        Properties p = new Properties();
        try {
            p.load(is);
            if(closeStream){
                is.close();
            }
            s = p.getProperty(propertyName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }
    /**
     * 如果Key不存在返回defaultValue反之返回Key的对应value
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:09
 	 * @param: props
 	 * @param: key
 	 * @param: defaultValue
 	 * @return: {@link String}
    **/
    public static String getString(Properties props, String key,
                                   String defaultValue) {
        String value = props.getProperty(key);
        if (StringUtils.isEmpty(value)) {
            return defaultValue;
        }
        return value;
    }
    /**
     * 采用Properties类取得属性文件对应值
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:10
 	 * @param: propertiesFileName 全路径
 	 * @param: propertyName 属性名
 	 * @return: {@link String} 根据属性名得到的属性值，如没有返回""
    **/
    public static String getValueByPropertyName(String propertiesFileName,
                                                String propertyName) throws FileNotFoundException {

        return getValueByPropertyName(new FileInputStream(propertiesFileName), propertyName);
    }
    /**
     * 获得属性文件key对应的
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:10
 	 * @param: is 输入流
 	 * @param: propertyName 属性名称
 	 * @return: {@link String}
    **/
    public static String getValueByPropertyName(InputStream is, String propertyName) {
        return getValueByPropertyName(is, propertyName, true);
    }
    /**
     * 调用getValueByResource方法读取 取propertiesFileName文件中名为propertyName的value
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:11
 	 * @param: propertiesFileName
 	 * @param: propertyName
 	 * @return: {@link String}
    **/
    public static String getValueByResource(String propertiesFileName,
                                            String propertyName) {
        return getValueByResource(propertiesFileName, propertyName, "");
    }
    /**
     * 通过ResourceUtil.getResourceAsStream读取propertiesFileName文件中名为propertyName的value
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:11
 	 * @param: propertiesFileName
 	 * @param: propertyName
 	 * @param: defaultValue
 	 * @return: {@link String}
    **/
    public static String getValueByResource(String propertiesFileName,
                                            String propertyName, String defaultValue) {
        String s = defaultValue;
        Properties p = new Properties();
        try {
            InputStream in = ResourceUtils
                    .getResourceAsStream(propertiesFileName);
            p.load(in);
            in.close();
            s = p.getProperty(propertyName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }
    /**
     * 通过FileInputStream读 取propertiesFileName文件中名为propertyName的value
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:12
 	 * @param: propertiesFileName
 	 * @param: propertyName
 	 * @param: defaultValue
 	 * @return: {@link String}
    **/
    public static String getValueByPropertyName(String propertiesFileName,
                                                String propertyName, String defaultValue) {
        String s = defaultValue;
        Properties p = new Properties();
        FileInputStream in;
        try {
            in = new FileInputStream(propertiesFileName);
            p.load(in);
            in.close();
            s = p.getProperty(propertyName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }
    /**
     * 获取属性文件Properties对象
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:12
 	 * @param: is
 	 * @return: {@link Properties}
    **/
    public static Properties getProperties(InputStream is) {
        Properties p = new Properties();
        try {
            p.load(is);
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return p;
    }
    /**
     * 更改属性文件的值，如果对应的属性不存在，则自动增加该属性
     * @author: <a href="mailto:fxsen@foxmail.com">Fxsen</a>
     * @date: 2022/8/3 20:14
 	 * @param: propertiesFileDir 目录路径
 	 * @param: propertiesFileName 文件名
 	 * @param: propertyName propertyName属性名
 	 * @param: propertyValue propertyValue将属性名更改成该属性值
 	 * @return: {@link boolean} 是否操作成功
    **/
    public static boolean changeValueByPropertyName(String propertiesFileDir,
                                                    String propertiesFileName, String propertyName, String propertyValue) {
        boolean writeOK = true;
        Properties p = new Properties();
        File file = new File(propertiesFileDir, propertiesFileName);
        if (!file.exists()) {
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            try {
                file.createNewFile();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        FileInputStream in;
        try {
            in = new FileInputStream(file);
            p.load(in);
            in.close();
            p.setProperty(propertyName, propertyValue);
            FileOutputStream out = new FileOutputStream(file);
            p.store(out, "");// 设置属性头
            out.flush();
            out.close();
        } catch (Exception e) {
            writeOK = false;
            e.printStackTrace();
        }
        return writeOK;
    }

    @Override
    public String getValue(String fileName, String key) {
        String activeFileName = getBySpringProfilesActive(fileName);
        try {
            String valueByKey = getValueByKey(activeFileName, key);
            if (StringUtils.isBlank(valueByKey)){
                valueByKey = getValueByKey(fileName, key);
            }
            return valueByKey;
        }catch (Exception e) {
            log.error(fileName + ":" + key + "不存在...");
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String getProperties(String key) {
        return this.getValue("application.properties", key);
    }

    @Override
    public String getYml(String key) {
        return this.getValue("application.yml", key);
    }

    private String getBySpringProfilesActive(String fileName){
        int pos = fileName.lastIndexOf(".");
        if (APPLICATION_PROPERTIES.equals(fileName)){
            String active = getValueByPropertyName(
                    ResourceUtils.getResourceAsStream(APPLICATION_PROPERTIES), "spring.profiles.active");
            fileName = fileName.substring(0, pos) + "-" + active +".properties";
        }
        if (APPLICATION_YML.equals(fileName)){
            InputStream input = ResourceUtils.getResourceAsStream("application.yml");
            String active = getYmlValue(input, "spring.profiles.active");
            fileName = fileName.substring(0, pos) + "-" + active +".properties";
        }
        return fileName;
    }
    private String getYmlValue(InputStream input, String key) {
        Yaml yaml = new Yaml();
        Object object = yaml.load(input);
        String[] strs = key.split("\\.");
        for (int i = 0; i < strs.length; i++) {
            object = parseYmlMap(object, strs[i]);
        }
        return object == null ? null : object.toString();
    }
    private Object parseYmlMap(Object obj, String key) {
        if(obj instanceof Map) {
            Map<String, Object> map = (Map<String, Object>)obj;
            return map.get(key);
        }
        return obj == null ? null : obj.toString();
    }
    private String getValueByKey(String fileName, String key) {
        String result = getValueByPropertyName(ResourceUtils.getResourceAsStream(fileName), key);
        if(StringUtils.isEmpty(result)) {
            if(fileName.endsWith(".properties")) {
                fileName = fileName.replace(".properties", ".yml");
            }
            InputStream input = ResourceUtils.getResourceAsStream(fileName);
            result = getYmlValue(input, key);
        }
        return result;
    }

    public static void main(String[] args) {
        getInstance().getYml("project-config.account.lock");
    }
}
